﻿'Nuestra clase USBDevice. Es simple y muy flexible.

'Atributos privados:
'   -ManejadorDEV
'   -RutaDEV
'   -ManejadorUSB
'Atributos públicos
'   -Estado

'Métodos públicos:
'   -Init(myGUID)               Inicializa el dispositivo USB. Requiere un GUID. Este es el que se especifica en el .INF del driver
'   -Send(SendedData)           Envía SendedData al dispositivo
'   -Receive(ReceivedData)      Recibe ReceivedData del dispositivo

Imports Microsoft.Win32.SafeHandles
Imports System.Runtime.InteropServices
Imports USBConverter.USBConverter.MSDNImports

Public Class USBDevice

    'Atributos
    '   Privados
    Private ManejadorDEV As SafeFileHandle
    Private RutaDEV As String
    Private ManejadorUSB As IntPtr
    '   Publicos
    Public Estado As Boolean

    'Métodos
    Public Function Init(ByVal myGUID As Guid) As Boolean

        Dim bResult As Boolean
        Dim requiredLength As Int32
        Dim Instance As Int32
        Dim deviceInfo As IntPtr
        Dim interfaceData As SP_DEVICE_INTERFACE_DATA
        Dim detailData As IntPtr

        '[1] Obtener el manejador del dispositivo (Handle) por medio del GUID del archivo .INF del controlador del dispositivo USB
        deviceInfo = SetupDiGetClassDevs( _
                    myGUID, _
                    IntPtr.Zero, _
                    IntPtr.Zero, _
                    DIGCF_PRESENT Or DIGCF_DEVICEINTERFACE)

        '[2] Enumerar la Interfaz del Dispositivo y obtener información sobre ella
        '       a) Obtenemos el tamaño real de la estructura, pues este varía. Véase el WinUSB Howto
        interfaceData.cbSize = Marshal.SizeOf(interfaceData)
        '       b)  Procedemos a enumerarla
        bResult = SetupDiEnumDeviceInterfaces( _
                    deviceInfo, _
                    IntPtr.Zero, _
                    myGUID, _
                    Instance, _
                    interfaceData)

        '[3] Obtener los datos detallados de la interfaz del dispositivo
        '       a) En el Howto, el detailData no tiene un tamaño fijo. Pasamos NULL en lugar de detailData; esto nos llena requiredLength
        SetupDiGetDeviceInterfaceDetail( _
                    deviceInfo, _
                    interfaceData, _
                    IntPtr.Zero, _
                    0, _
                    requiredLength, _
                    IntPtr.Zero)
        '       b) Como ya sabemos de que tamaño debe ser detailData, con punteros lo creamos teniendo en cuenta dicho tamaño
        detailData = Marshal.AllocHGlobal(requiredLength)
        Marshal.WriteInt32(detailData, CInt(IIf((IntPtr.Size = 4), 4 + Marshal.SystemDefaultCharSize, 8)))
        '       c) Ya 'encajamos' el detailData con el requiredLenght, ahora repodemos recibir ya los datos detallados
        bResult = SetupDiGetDeviceInterfaceDetail _
                    (deviceInfo, _
                    interfaceData, _
                    detailData, _
                    requiredLength, _
                    requiredLength, _
                    IntPtr.Zero)
        '       d) Tenemos detailData, pero nos interesa la ruta del dispositivo, es decir, RutaDEV
        '           -)Saltamos 4 bytes para obtener un puntero a la ruta del dispositivo
        Dim pRutaDEV As IntPtr = New IntPtr(detailData.ToInt32 + 4)
        '           -)Pasamos a RutaDEV lo contenido en el puntero
        RutaDEV = Marshal.PtrToStringAuto(pRutaDEV)
        '       e)Liberamos la memoria reservada por AllocHGlobal.
        Marshal.FreeHGlobal(detailData)

        '[4] Obtenemos el manejador del dispositivo ManejadorDEV pasando la ruta del dispositivo RutaDEV a CreateFile
        ManejadorDEV = CreateFile _
                (RutaDEV, _
                GENERIC_WRITE Or GENERIC_READ, _
                FILE_SHARE_READ Or FILE_SHARE_WRITE, _
                IntPtr.Zero, _
                OPEN_EXISTING, _
                FILE_ATTRIBUTE_NORMAL Or FILE_FLAG_OVERLAPPED, _
                0)

        '[5] Con el manejador del archivo del dispositivo, obtenemos un manejador tipo WinUSB, llamado ManejadorUSB
        bResult = WinUsb_Initialize(ManejadorDEV, ManejadorUSB)

        '[6] Liberamos recursos
        SetupDiDestroyDeviceInfoList(deviceInfo)

        Estado = bResult
        Return bResult
    End Function
    Public Function Finish() As Boolean
        Dim bResult As Boolean

        bResult = WinUsb_Free(ManejadorUSB)     'Cerramos todos los recursos consumidos por WinUSB_Init
        CloseHandle(ManejadorDEV)               'Cerramos el archivo Handle creado por el CreateFile

        Estado = Not bResult                    'Negamos
        Return bResult
    End Function
    Public Function Send(ByVal SendedData() As Byte) As Boolean

        'Declaración de variables
        Dim PipeOut As Byte = &H1       'Pipe de salida del GUI
        Dim sizeData As Int32
        Dim bResult As Boolean


        If Estado = True Then
            sizeData = SendedData.GetLength(0)
            bResult = WinUsb_WritePipe(ManejadorUSB, PipeOut, SendedData, sizeData, IntPtr.Zero, IntPtr.Zero)
        End If


        Return bResult

    End Function
    Public Function Receive(ByVal ReceivedData() As Byte) As Boolean

        'Declaración de variables
        Dim PipeIn As Byte = &H81       'Pipe de entrada al GUI
        Dim sizeData As Int32
        Dim bResult As Boolean


        If Estado = True Then
            sizeData = ReceivedData.GetLength(0)
            bResult = WinUsb_ReadPipe(ManejadorUSB, PipeIn, ReceivedData, sizeData, IntPtr.Zero, IntPtr.Zero)
        End If

     
        Return bResult

    End Function

End Class
